package com.mdd.front.service.pay.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.service.WxPayService;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.IcbcClient;
import com.icbc.api.IcbcConstants;
import com.icbc.api.internal.util.internal.util.fastjson.JSON;
import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1;
import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1;
import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1;
import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineMerrefundResponseV1;
import com.mdd.common.entity.order.Order;
import com.mdd.common.entity.recharge.RechargeOrder;
import com.mdd.common.entity.refund.OrderRefund;
import com.mdd.common.entity.user.UserAuth;
import com.mdd.common.enums.OrderPayStatusEnum;
import com.mdd.common.enums.OrderStatusEnum;
import com.mdd.common.exception.OperateException;
import com.mdd.common.mapper.order.OrderMapper;
import com.mdd.common.mapper.recharge.RechargeOrderMapper;
import com.mdd.common.mapper.refund.OrderRefundMapper;
import com.mdd.common.mapper.user.UserAuthMapper;
import com.mdd.common.utils.IpUtil;
import com.mdd.common.utils.SnUtils;
import com.mdd.front.LikeFrontThreadLocal;
import com.mdd.front.constant.YmlConstant;
import com.mdd.front.service.order.IOrderService;
import com.mdd.front.service.pay.ICBCService;
import com.mdd.front.vo.wxpay.WxPayCreateOrderRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

@Service
@Slf4j
@Data
public class ICBCServiceImpl implements ICBCService {

	@Resource
	private IcbcClient client;

	@Resource
	private IOrderService iOrderService;

	@Resource
	private RechargeOrderMapper rechargeOrderMapper;

	@Resource
	private UserAuthMapper userAuthMapper;

	@Resource(name = "mpWxPayService")
	private WxPayService wxPayService;

	@Resource
	private YmlConstant ymlConstant;

	@Resource
	private OrderRefundMapper orderRefundMapper;

	@Resource
	private IOrderService orderService;

	@Resource
	private OrderMapper orderMapper;

	@Override
	@Transactional
	public WxPayUnifiedOrderV3Result.JsapiResult getICBCPayParam(WxPayCreateOrderRequest wxPayCreateOrderRequest) {
		Order order = null;
		switch (wxPayCreateOrderRequest.getScene()) {
			case "order":
				order = this.iOrderService.getById(Long.valueOf(wxPayCreateOrderRequest.getOrderId()), LikeFrontThreadLocal.getUserId());
				Assert.notNull(order, "订单不存在");
				break;
			case "recharge":
				RechargeOrder rechargeOrder = rechargeOrderMapper.selectOne(new QueryWrapper<RechargeOrder>()
						.eq("id", wxPayCreateOrderRequest.getOrderId())
						.eq("order_status", OrderStatusEnum.WAIT_PAY.getStatus())
						.eq("pay_status", OrderPayStatusEnum.WAIT_PAY.getStatus())
						.eq("user_id", LikeFrontThreadLocal.getUserId())
						.last("limit 1"));
				Assert.notNull(rechargeOrder, "订单不存在");
				break;
			default:
				throw new OperateException("不支持当前订单类型");
		}
		log.info("ICBC返回的参数是： {}", order.getResponseData());
		if (Objects.nonNull(order) && Objects.nonNull(order.getResponseData())) {
			WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = new WxPayUnifiedOrderV3Result.JsapiResult();
			JSONObject jsonObject = JSONUtil.parseObj(order.getResponseData());
			return getJsapiResult(jsapiResult, jsonObject);
		}
		String substring = UUID.randomUUID().toString().substring(20);
		UserAuth userAuth = userAuthMapper.selectOne(new QueryWrapper<UserAuth>()
				.select("id,openid")
				.eq("user_id", LikeFrontThreadLocal.getUserId())
				.last("limit 1"));
		String openid = userAuth.getOpenid();
		BigDecimal bigDecimal = new BigDecimal(order.getOrderAmount().toString());
		BigDecimal multiply = bigDecimal.multiply(new BigDecimal(100));
		Date date = new Date();
		String dateFormat = DateUtil.format(date, "yyyy-MM-dd'T'HH:mm:ss");
		log.info("支付的订单是： {}", order);
		WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = getJsapiResult(order, dateFormat, substring, multiply, openid);
		if (jsapiResult != null) return jsapiResult;
		return null;
	}

	/**
	 *  封装ICBC支付的请求
	 * */
	private WxPayUnifiedOrderV3Result.JsapiResult getJsapiResult(Order order, String dateFormat, String substring, BigDecimal multiply, String openid) {
		// 获取工行的数据
		CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1();
		request.setServiceUrl(ymlConstant.serviceUrl + ymlConstant.aggregatepayV1);
		// 5、根据测试环境和生产环境替换相应ip和端口
		//根据测试环境和生产环境替换相应ip和端口
		// request.setServiceUrl("https://[需替换]环境对应的ip和端口/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1");
		CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz();
		request.setBizContent(bizContent);
		bizContent.setExpire_time("3600"); // 设置订单失效时间为3600秒
		//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
		bizContent.setMer_id(ymlConstant.merId);   // 需要指定的参数
		bizContent.setMer_prtcl_no(ymlConstant.merPrtclNo);// 需要指定的参数
		bizContent.setOut_trade_no(order.getSn());
		//支付方式，9-微信；10-支付宝；13-云闪付
		bizContent.setPay_mode("9");
		//收单接入方式，5-APP，7-微信公众号，8-支付宝生活号，9-微信小程序
		bizContent.setAccess_type("9");
		//交易日期时间，格式为yyyy-MM-dd’T’HH:mm:ss
		bizContent.setOrig_date_time(dateFormat);
		//设备号
		bizContent.setDecive_info("WEB");
		//商品描述
		bizContent.setBody(order.getUserRemark() + substring);
		//交易币种，目前工行只支持使用人民币（001）支付
		bizContent.setFee_type("001");
		bizContent.setSpbill_create_ip(IpUtil.getIpAddress());
		//订单金额，单位为分
		bizContent.setTotal_fee(multiply.intValue() + "");
		//异步通知商户URL，端口必须为443或80
		bizContent.setMer_url(ymlConstant.merUrl);
		//取值“HS”：在交易完成后将通知信息，主动发送给商户，发送地址为mer_url指定地址； 取值“AG”：在交易完成后不通知商户
		bizContent.setNotify_type("HS");
		bizContent.setShop_appid(ymlConstant.shopAppid);
		bizContent.setOpen_id(openid);
		CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response;
		try {
			log.info("支付请求为： {}", request.getBizContent());
			response = client.execute(request, System.currentTimeMillis() + ""); //msgId消息通讯唯一编号，要求每次调用独立生成，APP级唯一
			if (response.getReturnCode() == 0) {
				// 将该订单请求返回成功的responsedata存到数据库中，方便用户下一次继续支付该订单
				Order orderParam = new Order();
				orderParam.setId(order.getId());
				String wx_data_package = response.getWx_data_package();
				orderParam.setResponseData(wx_data_package);
				orderMapper.updateById(orderParam);
				// 业务成功处理，请根据接口文档用response.getxxx()获取同步返回的业务数据
				WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = new WxPayUnifiedOrderV3Result.JsapiResult();
				JSONObject jsonObject = JSONUtil.parseObj(wx_data_package);
				return getJsapiResult(jsapiResult, jsonObject);
			} else {
				// 失败
				log.error("工行调用获取结果失败，response为: {}", JSON.toJSONString(response));
				log.error("ReturnCode: {}", response.getReturnCode());
				log.error("ReturnMsg: {}", response.getReturnMsg());
			}
		} catch (IcbcApiException e) {
			log.error("工行api调用失败： {}", e);
		}
		return null;
	}

	/**
	 * 封装支付的请求结果
	 */
	private WxPayUnifiedOrderV3Result.JsapiResult getJsapiResult(WxPayUnifiedOrderV3Result.JsapiResult jsapiResult, JSONObject jsonObject) {
		jsapiResult.setAppId(jsonObject.getStr("appid"));
		jsapiResult.setTimeStamp(jsonObject.getStr("timestamp"));
		jsapiResult.setSignType(jsonObject.getStr("signType"));
		jsapiResult.setPaySign(jsonObject.getStr("sign"));
		jsapiResult.setNonceStr(jsonObject.getStr("noncestr"));
		jsapiResult.setPackageValue(jsonObject.getStr("package"));
		return jsapiResult;
	}

	/**
	public void payCashierCode(Order order, BigDecimal multiply, String dateFormat) {
		// 4、需传入appid，私钥，字符集
		UiIcbcClient client = new UiIcbcClient(ymlConstant.appId, IcbcConstants.SIGN_TYPE_RSA2, ymlConstant.icbcPrivateKey,
				IcbcConstants.CHARSET_UTF8);
		CardbusinessB2cOnlineMultipayconsumptionRequestV1 request = new
				CardbusinessB2cOnlineMultipayconsumptionRequestV1();


		// 5、根据测试环境和生产环境替换相应ip和端口
		request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/b2c/online/multipayconsumption/V1");
		CardbusinessB2cOnlineMultipayconsumptionRequestV1.CardbusinessB2cOnlineMultipayconsumptionRequestV1Biz bizContent = new
				CardbusinessB2cOnlineMultipayconsumptionRequestV1.CardbusinessB2cOnlineMultipayconsumptionRequestV1Biz();
		request.setBizContent(bizContent);
// 6、请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
		bizContent.setOutTradeNo(order.getSn());
		bizContent.setMerId(ymlConstant.mchId);
		bizContent.setMerPrtclNo(ymlConstant.merPrtclNo);
		bizContent.setAccessType("9");
		bizContent.setCurType("001");
		bizContent.setAmount(multiply.intValue() + "");
		bizContent.setIcbcAppid(ymlConstant.appId);
		bizContent.setNotifyType("HS");
		bizContent.setResultType("0");
		bizContent.setOrderDate(dateFormat);
		bizContent.setGoodsName(order.getSn());
		bizContent.setBody(StrUtil.nullToDefault(order.getOrderRemarks(), "商品名称： test"));
		bizContent.setShopAppid(ymlConstant.shopAppid);
		//bizContent.setMerUrl(merUrl);
		//bizContent.setReturnUrl("xxx");
		//bizContent.setQuitUrl("xxx");
		//bizContent.setExpireTime("xxx");
		//通知方式为HS时有效。取值“0”：无论支付成功或者失败，银行都向商户发送交易通知信息；取值“1”，银行只向商户发送交易成功的通知信息
		//bizContent.setAttach("xxx");
//        bizContent.setOrderApdInf("xxx");
//        bizContent.setSaledepname("xxx");
//        bizContent.setSaledepnameen("xxx");
//        bizContent.setRemark("xxx");
//        bizContent.setLanguage("xxx");
//        bizContent.setPayLimit("xxx");
//        bizContent.setMerAcct("xxx");
//        bizContent.setInstallmentTimes("xxx");
//        bizContent.setMerchantInfo("xxx");
//        bizContent.setH5Flag("xxx");
//        bizContent.setAutoReferSec("xxx");
//        bizContent.setWalletFlag("xxx");
//        bizContent.setExternalAppId("xxx");
//        bizContent.setCustId("xxx");
//        bizContent.setMobile("xxx");
//        bizContent.setCreditType("xxx");
//        bizContent.setCustCheckflag("xxx");
//        bizContent.setCustName("xxx");
//        bizContent.setCustCertType("xxx");
//        bizContent.setCustCertNo("xxx");
//        bizContent.setAllocateCardno("xxx");
//        bizContent.setBizType("xxx");
//        bizContent.setExtendInfo("xxx");
//        bizContent.setIsApplepay("xxx");
//        bizContent.setWxpay_detail("xxx");
//        bizContent.setAlipay_detail("xxx");
//        bizContent.setScheme("xxx");
//        bizContent.setPackage_name("xxx");
		try {
			String s = client.buildPostForm(request);
			log.info(s);
		} catch (IcbcApiException e) {
			e.printStackTrace();
		}

	}
*/

	@Override
	public void refund(OrderRefund order, Long userId) throws IcbcApiException {
		//签名类型为RSA2时，需传入appid，私钥和网关公钥，签名类型使用定值IcbcConstants.SIGN_TYPE_RSA2，其他参数使用缺省值
		DefaultIcbcClient client = new DefaultIcbcClient(ymlConstant.appId, IcbcConstants.SIGN_TYPE_RSA2, ymlConstant.icbcPrivateKey, ymlConstant.icbcPublicKey);
		CardbusinessAggregatepayB2cOnlineMerrefundRequestV1 request = new CardbusinessAggregatepayB2cOnlineMerrefundRequestV1();
		//根据测试环境和生产环境替换相应ip和端口
		request.setServiceUrl(ymlConstant.serviceUrl + ymlConstant.icbcRefundqry);
		//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
		CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz();
		request.setBizContent(bizContent);
		bizContent.setOrder_id(order.getTransactionId());//消费工行订单号,工行订单号，商户订单号或行内订单号必须其中一个不为空
		bizContent.setMer_id(ymlConstant.merId);//商户编号-必输项
		//bizContent.setOut_trade_no(order.getSn());//商户订单号,工行订单号，商户订单号或行内订单号必须其中一个不为空
		String sn = SnUtils.getRefundOrderSn();
		bizContent.setOuttrx_serial_no(sn);//外部退货流水号-必输项
		bizContent.setRet_total_amt(order.getOrderAmount().multiply(new BigDecimal(100)).intValue()+"");//退货总金额-必输项
		bizContent.setTrnsc_ccy("001");//交易币种-必输项
		bizContent.setOrder_apd_inf("");
		bizContent.setIcbc_appid(ymlConstant.appId);
		CardbusinessAggregatepayB2cOnlineMerrefundResponseV1 response;
		log.info("开始调用ICBC退款接口请求参数是: {}", bizContent);
		response = client.execute(request, System.currentTimeMillis() + "");//msgId消息通讯唯一编号，要求每次调用独立生成，APP级唯一
		log.info("调用ICBC退款接口成功 ");
		if (response.isSuccess()) {
			// 业务成功处理，请根据接口文档用response.getxxx()获取同步返回的业务数据
			log.info("退款成功： ReturnCode:{}", response.getReturnCode());
			log.info("退款成功： response:{}", response);
		} else {
			// 失败
			log.error("退款失败：ReturnCode:{}", response.getReturnCode());
			log.error("退款失败: ReturnMsg:{}", response.getReturnMsg());
		}
	}


}
